﻿Function.RegisterNamespace("Test.xUnit.js");

[Import("../../Source/xUnit.js/Mocks.js")]
[Fixture]
Test.xUnit.js.Mocks=function(){
    [Fixture]
    function GetMock(){
        [Fact]
        function ThrowsIfTargetIsUndefined(){
            var expected="xUnit.js.Mocks.GetMock: 'target' must be a valid Object.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock();
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTargetIsNull(){
            var expected="xUnit.js.Mocks.GetMock: 'target' must be a valid Object.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock(null);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTargetIsBooleanLiteral(){
            var expected="xUnit.js.Mocks.GetMock: 'target' must be a valid Object.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock(true);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTargetIsNumberLiteral(){
            var expected="xUnit.js.Mocks.GetMock: 'target' must be a valid Object.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock(1);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTargetIsStringLiteral(){
            var expected="xUnit.js.Mocks.GetMock: 'target' must be a valid Object.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock("string");
            });

            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfMemberIsNull(){
            var expected="xUnit.js.Mocks.GetMock: 'member' must be a valid String.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock({},null);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMemberIsUndefined(){
            var expected="xUnit.js.Mocks.GetMock: 'member' must be a valid String.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock({});
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMemberIsArray(){
            var expected="xUnit.js.Mocks.GetMock: 'member' must be a valid String.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock({},[]);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMemberIsBoolean(){
            var expected="xUnit.js.Mocks.GetMock: 'member' must be a valid String.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock({},null);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMemberIsError(){
            var expected="xUnit.js.Mocks.GetMock: 'member' must be a valid String.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock({},new Error());
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMemberIsFunction(){
            var expected="xUnit.js.Mocks.GetMock: 'member' must be a valid String.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock({},function(){});
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMemberIsObject(){
            var expected="xUnit.js.Mocks.GetMock: 'member' must be a valid String.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock({},{});
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMemberIsNumber(){
            var expected="xUnit.js.Mocks.GetMock: 'member' must be a valid String.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock({},1);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMemberIsEmptyString(){
            var expected="xUnit.js.Mocks.GetMock: 'member' must be a valid String.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMock({},"");
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function CallsGetMocksIfValid(){
            var targetGetMocks=xUnit.js.Mocks.GetMocks;
            xUnit.js.Mocks.GetMocks=function(){
                actual=true;
            }
            var actual=false;

            xUnit.js.Mocks.GetMock({},"member","mock");
            xUnit.js.Mocks.GetMocks=targetGetMocks;

            Assert.True(actual);
        }

        [Fact]
        function PassesTargetToGetMocks(){
            var targetGetMocks=xUnit.js.Mocks.GetMocks;
            xUnit.js.Mocks.GetMocks=function(target){
                actual=target;
            }
            var expected={};
            var actual=null;

            xUnit.js.Mocks.GetMock(expected,"member","mock");
            xUnit.js.Mocks.GetMocks=targetGetMocks;

            Assert.Equal(expected,actual);
        }

        [Fact]
        function PassesPropertyBagWithMemberMockToGetMocks(){
            var targetMember="member";
            var targetGetMocks=xUnit.js.Mocks.GetMocks;
            xUnit.js.Mocks.GetMocks=function(target,targetMocks){
                actual=targetMocks[targetMember];
            }
            var expected="expected";
            var actual=null;

            xUnit.js.Mocks.GetMock({},targetMember,expected);
            xUnit.js.Mocks.GetMocks=targetGetMocks;

            Assert.Equal(expected,actual);
        }

        [Fact]
        function MocksLanguageFeature(){
            var expected="expected";
            var mockDate=Mocks.GetMock(Object.Global(),"Date",function(){
                this.getTime=function(){
                    return expected;
                }
            });
            var actual=null;

            mockDate(function(){
                actual=new Date().getTime();
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ResetsMockedLanguageFeature(){
            var expected=Date;
            var mockDate=Mocks.GetMock(Object.Global(),"Date",function(){
                this.getTime=function(){
                    return 0;
                }
            });

            mockDate(function(){
                new Date().getTime();
            });
            var actual=Date;

            Assert.Equal(expected,actual);
        }
    }

    [Fixture]
    function GetMocks(){
        [Fact]
        function ThrowsIfTargetIsUndefined(){
            var expected="xUnit.js.Mocks.GetMocks: 'target' must be a valid Object.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks();
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTargetIsNull(){
            var expected="xUnit.js.Mocks.GetMocks: 'target' must be a valid Object.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks(null);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTargetIsBooleanLiteral(){
            var expected="xUnit.js.Mocks.GetMocks: 'target' must be a valid Object.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks(true);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTargetIsNumberLiteral(){
            var expected="xUnit.js.Mocks.GetMocks: 'target' must be a valid Object.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks(1);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfTargetIsStringLiteral(){
            var expected="xUnit.js.Mocks.GetMocks: 'target' must be a valid Object.";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks("string");
            });

            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfMockeryIsNull(){
            var expected="xUnit.js.Mocks.GetMock: 'mockeries' must be a valid Object containing member to mock mappings.";
        
            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks({},null);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMockeryIsUndefined(){
            var expected="xUnit.js.Mocks.GetMock: 'mockeries' must be a valid Object containing member to mock mappings.";
        
            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks({});
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMockeryIsArray(){
            var expected="xUnit.js.Mocks.GetMock: 'mockeries' must be a valid Object containing member to mock mappings.";
        
            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks({},[]);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMockeryIsBoolean(){
            var expected="xUnit.js.Mocks.GetMock: 'mockeries' must be a valid Object containing member to mock mappings.";
        
            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks({},true);
            });

            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfMockeryIsError(){
            var expected="xUnit.js.Mocks.GetMock: 'mockeries' must be a valid Object containing member to mock mappings.";
        
            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks({},new Error());
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMockeryIsFunction(){
            var expected="xUnit.js.Mocks.GetMock: 'mockeries' must be a valid Object containing member to mock mappings.";
        
            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks({},function(){});
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMockeryIsNumber(){
            var expected="xUnit.js.Mocks.GetMock: 'mockeries' must be a valid Object containing member to mock mappings.";
        
            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks({},1);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMockIsCalledWithArrayDelegate(){
            var expected="xUnit.js.Mocks.Mockery: 'during' must be a valid Function pointer.";
        
            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks({},{})([]);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMockIsCalledWithBooleanDelegate(){
            var expected="xUnit.js.Mocks.Mockery: 'during' must be a valid Function pointer.";
        
            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks({},{})(true);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMockIsCalledWithErrorDelegate(){
            var expected="xUnit.js.Mocks.Mockery: 'during' must be a valid Function pointer.";
        
            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks({},{})(new Error());
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMockIsCalledWithNumberDelegate(){
            var expected="xUnit.js.Mocks.Mockery: 'during' must be a valid Function pointer.";
        
            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks({},{})(1);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfMockIsCalledWithObjectDelegate(){
            var expected="xUnit.js.Mocks.Mockery: 'during' must be a valid Function pointer.";
        
            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks({},{})({});
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsMemberOnArray(){
            var target=[];
            var targetMockery={};
            var targetMember="member";
            var expected="expected";
            targetMockery[targetMember]=expected;
            var actual=null;

            xUnit.js.Mocks.GetMocks(target,targetMockery)(function(){
                actual=target[targetMember];
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsMemberOnBooleanObject(){
            var target=new Boolean();
            var targetMockery={};
            var targetMember="member";
            var expected="expected";
            targetMockery[targetMember]=expected;
            var actual=null;

            xUnit.js.Mocks.GetMocks(target,targetMockery)(function(){
                actual=target[targetMember];
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsMemberOnError(){
            var target=new Error();
            var targetMockery={};
            var targetMember="member";
            var expected="expected";
            targetMockery[targetMember]=expected;
            var actual=null;

            xUnit.js.Mocks.GetMocks(target,targetMockery)(function(){
                actual=target[targetMember];
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsMemberOnFunction(){
            var target=function(){};
            var targetMockery={};
            var targetMember="member";
            var expected="expected";
            targetMockery[targetMember]=expected;
            var actual=null;

            xUnit.js.Mocks.GetMocks(target,targetMockery)(function(){
                actual=target[targetMember];
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsMemberOnNumberObject(){
            var target=new Number();
            var targetMockery={};
            var targetMember="member";
            var expected="expected";
            targetMockery[targetMember]=expected;
            var actual=null;

            xUnit.js.Mocks.GetMocks(target,targetMockery)(function(){
                actual=target[targetMember];
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsMemberOnObject(){
            var target={};
            var targetMockery={};
            var targetMember="member";
            var expected="expected";
            targetMockery[targetMember]=expected;
            var actual=null;

            xUnit.js.Mocks.GetMocks(target,targetMockery)(function(){
                actual=target[targetMember];
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsMemberOnStringObject(){
            var target=new String();
            var targetMockery={};
            var targetMember="member";
            var expected="expected";
            targetMockery[targetMember]=expected;
            var actual=null;

            xUnit.js.Mocks.GetMocks(target,targetMockery)(function(){
                actual=target[targetMember];
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function RemovesMemberAfterMock(){
            var target={};
            var targetMockery={};
            var targetMember="member";
            var expected=undefined;
            targetMockery[targetMember]=expected;
            var actual="actual";

            xUnit.js.Mocks.GetMocks(target,targetMockery)(function(){});
            actual=target[targetMember];

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ResetsMemberAfterMock(){
            var target={};
            var targetMockery={};
            var targetMember="member";
            var expected="expected";
            target[targetMember]=expected;
            targetMockery[targetMember]="unexpected";
            var actual=null;

            xUnit.js.Mocks.GetMocks(target,targetMockery)(function(){});
            actual=target[targetMember];

            Assert.Equal(expected,actual);
        }

        [Fact]
        function RethrowsExceptions(){
            var expected="expected";

            var actual=Record.Exception(function(){
                xUnit.js.Mocks.GetMocks({},{"member":"mock"})(function(){
                    throw expected;
                });
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ResetsMemberIfExceptionIsThrown(){
            var target={};
            var targetMockery={};
            var targetMember="member";
            var expected="expected";
            target[targetMember]=expected;
            targetMockery[targetMember]="unexpected";

            Record.Exception(function(){
                xUnit.js.Mocks.GetMocks(target,targetMockery)(function(){
                    throw "error";
                });
            });
            var actual=target[targetMember];

            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsMultipleMembers(){
            var target={};
            var targetMockery={
                "member1":"mockery1",
                "member2":{mockery:2},
                "member3":function(){}
            };
            var expected=Object.Copy({},targetMockery);
            var actual=null;

            xUnit.js.Mocks.GetMocks(target,targetMockery)(function(){
                actual=Object.Copy({},target);
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsMockedMemberReferenceOnMock(){
            var target={};
            var targetMockery={};
            var targetMember="member";
            var expected="expected";
            target[targetMember]=expected;
            targetMockery[targetMember]={mock:"mock"};
            var actual=null;

            xUnit.js.Mocks.GetMocks(target,targetMockery)(function(){
                actual=target[targetMember].Mocked;
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsScopeOfMockedMethodReferenceToTarget(){
            var expected={};
            var targetMockery={};
            var targetMember="member";
            expected[targetMember]=function(){
                actual=this;
            };
            targetMockery[targetMember]={mock:"mock"};
            var actual=null;

            xUnit.js.Mocks.GetMocks(expected,targetMockery)(function(){
                expected[targetMember].Mocked();
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function PassesAdditionalParametersToMockDelegate(){
            var target={};
            var targetMockery={};
            var targetMember="member";
            var expected="expected";
            targetMockery[targetMember]={mock:"mock"};
            var actual=null;

            xUnit.js.Mocks.GetMocks(target,targetMockery)(function(targetParameter){
                actual=targetParameter;
            },expected);

            Assert.Equal(expected,actual);        
        }

    }

    [Fixture]
    function Mock(){
        [Fact]
        function ReturnsExecutableChain(){
            var actual=Mocks.Mock();

            Assert.Type(Function,actual);
        }

        [Fact]
        function ExecutesTargetMethod(){
            var expected="expected";
            var actual;

            Mocks.Mock()(function(){
                actual=expected;
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsTargetMethodReturnValue(){
            var expected="expected";
            
            var actual=Mocks.Mock()(function(){
                return expected;
            });

            Assert.Equal(expected,actual);
        }

        var mockeryData=[
            {mocks:[null],position:1},
            {mocks:[Mocks.GetMock({},"mock"),null],position:2},
            {mocks:[Mocks.GetMock({},"mock"),Mocks.GetMock({},"mock"),null],position:3}
        ];
        [Fact, Data(mockeryData)]
        function ThrowsOnInvalidMockery(data){
            var expected="xUnit.js.Mocks.Mock: 'mock' must be a valid mockery, at position '"+data.position+"'.";

            var actual=Record.Exception(function(){
                Mocks.Mock(data.mocks[0],data.mocks[1],data.mocks[2]);
            });

            Assert.Equal(expected,actual);           
        }

        [Fact]
        function InvokesMock(){
            var expected="expected";
            var actual;
            var targetMock=Mocks.GetMock(Object.Global(),"globalExpected",expected);

            Mocks.Mock(targetMock)(function(){
                actual=globalExpected;
            });
        
            Assert.Equal(expected,actual);
        }

        [Fact]
        function InvokesMultipleMocks(){
            var expected=6;
            var actual;
            var targetMocks=[
                Mocks.GetMock(Object.Global(),"globalOne",1),
                Mocks.GetMock(Object.Global(),"globalTwo",2),
                Mocks.GetMock(Object.Global(),"globalThree",3)
            ];

            Mocks.Mock(targetMocks[0],targetMocks[1],targetMocks[2])(function(){
                actual=globalOne+globalTwo+globalThree;
            });
        
            Assert.Equal(expected,actual);
        }

        [Fact]
        function CanOverridePreviousMocks(){
            var expected="expected";
            var actual;
            var targetMocks=[
                Mocks.GetMock(Object.Global(),"globalExpected","unexpected"),
                Mocks.GetMock(Object.Global(),"globalExpected",expected),
            ];

            Mocks.Mock(targetMocks[0],targetMocks[1])(function(){
                actual=globalExpected;
            });
        
            Assert.Equal(expected,actual);
        }
    }
}